import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { Form, Row, Col, ConfigProvider } from 'antd';
import { get } from 'object-path';
import cn from 'classnames';
import { groupBy } from 'lodash';
import { FormContainer } from '@/components/UserForm/FormContainer';
import rulesConfig from './rules';
import renderChildren from './childrens';
import renderComponent from './components';
import styles from './JsonForm.less';

const NO_TITLE = 'noTitle';

/**
 * 动态表单组件
 */
const JsonForm = ({ data, form, onChange, inline, fetching, layout, disabled }) => {
    const { getFieldDecorator } = form;
    const { labelCol, wrapperCol } = layout;
    const { span: labelSpan } = labelCol;
    const { span: wrapperSpan } = wrapperCol;
    let { fields } = data;

    // 合并 name 相同的字段为数组，比如实施范围中，companyName 与 companyId
    fields = fields.reduce((prev, cur) => {
        const last = prev[prev.length - 1];
        if (last) {
            if (Array.isArray(last) && last[0].name === cur.name) {
                return [...prev.slice(0, prev.length - 1), [...last, cur]];
            }
            if (last.name === cur.name) {
                return [...prev.slice(0, prev.length - 1), [last, cur]];
            }
        }
        return prev.concat(cur);
    }, []);

    // 合并 Title，用于归类表单内容，比如，基础信息
    fields = groupBy(fields, item => {
        if (!Array.isArray(item)) {
            const { params = {} } = item;
            const { title } = params;

            return title || NO_TITLE;
        }
        const { params = {} } = item[0];
        const { title } = params;
        return title || NO_TITLE;
    });

    const dealRules = (rules, curField) => {
        if (!rules) return rules;
        return rules.map(item => {
            if (typeof item.required !== 'boolean' && item.required && get(rulesConfig, item.required)) {
                return get(rulesConfig, item.required)(fields, curField, form, item.message || '');
            }
            return {
                ...item,
                message: item.message || ''
            };
        });
    };

    const renderItem = item => {
        const { type, readOnly, params = {} } = item;
        const { component = {} } = params;
        const { props = {}, config = {}, conditionProps } = component;
        const { rules = [], ...restConfig } = config;
        const { placeholder, disabled: itemDisabled = false, ...restProps } = props;
        const finalRules = dealRules(rules, item);

        // 临时对特定模块的数值进行限制
        let extraProps = {};
        if (params.title === '薪资福利' && item.type === 'antd.InputNumber') {
            extraProps = { max: 99999999, precision: 2 };
        }

        const Component = renderComponent(type);

        if (type !== 'span' && !Component) {
            throw new Error(`没有${type}类型的组件，请检查清楚！`);
        }

        const userProps = conditionProps && conditionProps(props, fetching);

        if (item.type === 'span') {
            return props.children;
        }

        return getFieldDecorator(item.id, {
            rules: finalRules || [],
            valuePropName: item.type === 'antd.Checkbox' ? 'checked' : 'value',
            ...restConfig
        })(
            <Component
                placeholder={props.placeholder}
                readOnly={readOnly}
                disabled={disabled || itemDisabled}
                onChange={val => onChange && onChange(item, val)}
                {...restProps}
                {...userProps}
                {...extraProps}
            >
                {renderChildren[type] && renderChildren[type](props, item)}
            </Component>
        );
    };

    return (
        <Fragment>
            <div className={styles.fixLine}>
                <ConfigProvider getPopupContainer={node => node.parentNode}>
                    {Object.keys(fields).map(key => {
                        const formContent = fields[key].map((field, index) => {
                            // 如果有存在 name 相同的表单项，默认取第一个的配置项
                            const { id, name, type, required, params = {} } = Array.isArray(field) ? field[0] : field;
                            const { itemProps = {}, condition, customWrapperSpan } = params;

                            const userItemProps = condition && condition(); // 注意，待废弃，新逻辑别用

                            // 组件是否独占一行
                            const oneLineTypes = ['antd.Input.TextArea', 'custom.Dimension'];
                            const isBlockComponent = oneLineTypes.includes(type) && !params.block;
                            const layoutSpanIsFn = typeof params.layoutSpan === 'function';
                            const paramsLayoutSpan = layoutSpanIsFn ? params.layoutSpan() : params.layoutSpan;
                            const isOneLineType = inline && (isBlockComponent || paramsLayoutSpan === 24);

                            const getClassName = () => {
                                const isCheckbox = field.type === 'antd.Checkbox';
                                const isLast = index === fields[key].length - 1;
                                const moreCheckbox = !isLast && fields[key][index + 1].type === 'antd.Checkbox';
                                return cn(styles.formItem, {
                                    [`flow__${id}`]: true,
                                    [styles.isCheckbox]: isCheckbox,
                                    [styles.nextIsCheckbox]: moreCheckbox,
                                    [styles.nestFormItem]: Array.isArray(field)
                                });
                            };

                            const renderFormItem = () => {
                                if (!Array.isArray(field)) {
                                    return renderItem(field, index);
                                }

                                return (
                                    <Row type="flex" gutter={8}>
                                        {field.map(item => {
                                            const componentCondition = get(item, 'params.component.condition', null);

                                            if (componentCondition && !componentCondition()) {
                                                return null;
                                            }

                                            const prev = get(item, 'params.component.prev', null);
                                            const after = get(item, 'params.component.after', null);
                                            const otherReasonId = get(item, 'id', '');
                                            return [
                                                prev && <Col key={`${item.id}_prev`}>{prev}</Col>,
                                                otherReasonId === 'otherReason' ? (
                                                    <Col
                                                        key={item.id}
                                                        style={{
                                                            flex: '2 0 100%',
                                                            ...item.params.customColStyle
                                                        }}
                                                    >
                                                        <Form.Item>{renderItem(item, index)}</Form.Item>
                                                    </Col>
                                                ) : (
                                                    <Col
                                                        key={item.id}
                                                        style={{ flex: 1, ...item.params.customColStyle }}
                                                    >
                                                        <Form.Item>{renderItem(item, index)}</Form.Item>
                                                    </Col>
                                                ),
                                                after && after() && (
                                                    <Col key={`${item.id}_after`} style={{ flex: 1 }}>
                                                        {after()}
                                                    </Col>
                                                )
                                            ];
                                        })}
                                    </Row>
                                );
                            };

                            return (
                                <Form.Item
                                    key={id}
                                    required={required}
                                    className={getClassName()}
                                    vvspan={isOneLineType && 24}
                                    label={name}
                                    labelCol={{
                                        span: isOneLineType ? labelSpan / 2 : labelSpan
                                    }}
                                    wrapperCol={{
                                        span: customWrapperSpan || (isOneLineType ? 24 - labelSpan / 2 : wrapperSpan)
                                    }}
                                    {...itemProps}
                                    {...userItemProps}
                                >
                                    {renderFormItem()}
                                </Form.Item>
                            );
                        });

                        const renderForm = () => {
                            if (inline) {
                                // 两列布局，如 offer 申请
                                return <FormContainer rowProps={{ gutter: 40 }}>{formContent}</FormContainer>;
                            }

                            return formContent;
                        };

                        const renderTitle = () => {
                            if (key === NO_TITLE) {
                                return null;
                            }
                            return (
                                <Row>
                                    <Col>
                                        <div className={styles.applyLine}></div>
                                        <h4 className={styles.head}>
                                            <span className={styles.title}>{key}</span>
                                            <span className={styles.subTitle}>
                                                {get(fields[key][0], 'params.subTitle', '')}
                                            </span>
                                        </h4>
                                    </Col>
                                </Row>
                            );
                        };

                        return (
                            <div className={styles.subContentBox}>
                                {renderTitle()}
                                {renderForm()}
                            </div>
                        );
                    })}
                </ConfigProvider>
            </div>
        </Fragment>
    );
};

JsonForm.propTypes = {
    data: PropTypes.object,
    form: PropTypes.any,
    layout: PropTypes.object,
    disabled: PropTypes.bool
};

JsonForm.defaultProps = {
    data: { fields: [] },
    form: {},
    layout: {},
    disabled: false
};

export default JsonForm;
